﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Noise.Utils;
using System.Drawing;

namespace NoiseLab
{
    public class LabPresenter
    {
        public LabPresenter(Main window)
        {
            _window = window;

            _window.Load += new EventHandler(Load);
            _window.AddModuleClicked += new EventHandler(AddModule);
            _window.CompleteAddModule += new AddModuleHandler(CompleteAddModule);
            _window.Render += new EventHandler(Render);
            _window.ModuleSelected += new EventHandler(ModuleSelected);

            GetLoadedModuleTypes();
        }

        void ModuleSelected(object sender, EventArgs e)
        {
            Noise.Modules.Module module = (Noise.Modules.Module)sender;
            _window.SetPropertyGridObject(module);
        }

        void Render(object sender, EventArgs e)
        {
            Noise.Modules.Module module = sender as Noise.Modules.Module;

            if( module != null)
            {
                NoiseMapBuilder builder = new PlanarNoiseMapBuilder(400, 400, 0, module, -5, 5, -5, 5, false);
                GradientColour colours = new GradientColour();
                colours.AddGradientPoint(-1.0, Color.DarkBlue);
                colours.AddGradientPoint(0.0, Color.DarkGreen);
                colours.AddGradientPoint(1.0, Color.White);
                ImageBuilder iBuilder = new ImageBuilder(builder.Build(), colours);
                _window.SetCurrentNoiseImage(iBuilder.Render());

            }
        }

        void CompleteAddModule(Type type, Noise.Modules.Module toModule)
        {
            if (toModule == null)
            {
                _modules.Add((Noise.Modules.Module)Activator.CreateInstance(type));
            }
            else
            {
                int i = FindFirstEmptySourceSlot(toModule);
                toModule.SetSourceModule(i, (Noise.Modules.Module)Activator.CreateInstance(type));
            }

            _window.SetModuleList(_modules);
        }

        private int FindFirstEmptySourceSlot(Noise.Modules.Module toModule)
        {
            for (int i = 0; i < toModule.ModuleCount; ++i)
            {
                if (toModule.Modules[i] == null) return i;
            }

            throw new Exception("Module full");
        }

        void AddModule(object sender, EventArgs e)
        {
            Noise.Modules.Module module = sender as Noise.Modules.Module;

            if (module == null || HasFreeModuleSlot(module))
            {
                _window.ShowModuleTypeSelector(_moduleTypes,module);
            }
            else
            {
                _window.ShowNoFreeModuleSlotsError();
            }
        }

        private bool HasFreeModuleSlot(Noise.Modules.Module module)
        {
            for (int i = 0; i < module.ModuleCount; ++i)
            {
                if (module.Modules[i] == null) return true;
            }
            return false;
        }

        void Load(object sender, EventArgs e)
        {
            SetModules();
        }

        private void SetModules()
        {
            _window.SetModuleList(_modules);
        }

        private void GetLoadedModuleTypes()
        {
            foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (Type typ in asm.GetTypes())
                {
                    if (typ.BaseType == typeof(Noise.Modules.Module) && !typ.IsAbstract)
                    {
                        _moduleTypes.Add(typ);
                    }
                }
            }

            _moduleTypes.Sort((a, b) => Comparer<string>.Default.Compare(a.Name, b.Name));
        }

        public Main Window
        {
            get
            {
                return _window;
            }
        }

        List<Type> _moduleTypes = new List<Type>();
        List<Noise.Modules.Module> _modules = new List<Noise.Modules.Module>();
        Main _window;
    }
}
